#include "ViewChangeAck.hpp"

using namespace BFT::order::messages;

ViewChangeAck::ViewChangeAck (uint32_t _view, uint32_t _vcreplica,
			      boost::shared_ptr<BFT::messages::Digest> _vcd, uint32_t _sendingReplica )
	: BFT::messages::MacArrayMessage(VIEW_CHANGE_ACK, computeSize(), _sendingReplica, 
					 BFT::Parameters::getOrderCount() )
{
	viewNo = _view;
	sourceReplica = _vcreplica;
	vcDigest = _vcd;
	
	int offset = getOffset();
	int bytes_size;
	boost::shared_ptr<char> bytes = getBytes(bytes_size);
	
	//write down the view number
	*(uint32_t*)(bytes.get()+offset) = htonl(viewNo);
	offset += VIEW_NUMBER_SIZE;
	
	//write down the source replica
	*(uint32_t*)(bytes.get()+offset) = htonl(sourceReplica);
	offset += SENDER_SIZE;
	
	//write down the digest
	boost::shared_ptr<char> digest_bytes = _vcd.get()->getBytes();
	memcpy( (void*)(bytes.get()+offset) , (const void*)(digest_bytes.get()) , DIGEST_SIZE );
	offset += DIGEST_SIZE;
		 
}

ViewChangeAck::ViewChangeAck(boost::shared_ptr<char> _bytes, int _bytes_size)
	: BFT::messages::MacArrayMessage(_bytes, _bytes_size)
{
	if(getTag() != VIEW_CHANGE_ACK)
	{	
		fprintf(stderr, "unable to build ViewChangeAck from bytes, invalid tag\n");
		exit(154);
	}
	
	int offset = getOffset();
	
	//read the view number
	viewNo = ntohl( *(uint32_t*)(_bytes.get()+offset) );
	offset += VIEW_NUMBER_SIZE;
	
	//read the source replica
	sourceReplica = ntohl( *(uint32_t*)(_bytes.get()+offset) );
	offset += SENDER_SIZE;
	
	//read the digest
	boost::shared_ptr<char> digest_bytes ( (char*)malloc(DIGEST_SIZE), free);
	memcpy( (void*)(digest_bytes.get()) , (const void*)(_bytes.get()+offset) , DIGEST_SIZE );
	offset += DIGEST_SIZE;
	vcDigest.reset( new BFT::messages::Digest(digest_bytes, DIGEST_SIZE));
	
	if ( (unsigned int)offset != _bytes_size - getAuthenticationSize())
	{
		fprintf(stderr,"trying to build a view change ack from invalid bytes\n");
		exit(155);
	}
}

bool ViewChangeAck::equals(boost::shared_ptr<ViewChangeAck> _other_vca)
{
	return BFT::messages::MacArrayMessage::equals(_other_vca)
		&& viewNo == _other_vca.get()->getViewNo()
		&& sourceReplica == _other_vca.get()->getChangingReplica()
		&& vcDigest.get()->equals(_other_vca.get()->getVCDigest());
}

uint32_t ViewChangeAck::computeSize()
{
	return VIEW_NUMBER_SIZE +
		SENDER_SIZE +
		DIGEST_SIZE;
}
